//-----------------------------------------------------------------------------
// Name: tut6main.cpp
// Auth: Bradford J. Smith
// Desc: This tutorial code shows more advanced input
//-----------------------------------------------------------------------------

#include "Assert.h"
#include "Billboard.h"
#include "Display.h"
#include "DisplayManager.h"
#include "Input.h"
#include "Player.h"
#include "LittleGuy.h"
#include "Systems.h"
#include "TuningParser.h"
#include "SharedFunctions.h"
#include "SharedConstants.h"
#include "corona/corona.h"

#include <gl/glut.h>
#include <gl/freeglut_ext.h>

//-----------------------------------------------------------------------------
// Globals:
//-----------------------------------------------------------------------------
corona::Image* gpBackgroundImageData;

//-----------------------------------------------------------------------------
// Function Prototypes:
//-----------------------------------------------------------------------------
void Initialize();
void InitDisplay();
void InitObjects();
void ShutdownObjects();
void InitResources();
void ShutdownResources();


//-----------------------------------------------------------------------------
// Desc: The main function of this programs serves to setup OpenGL, initialize
//			the program, set up all the callback functions, and start the 
//			event loop.
int main(int argc, char* argv[])
{
	InitSystems();

	std::string titleBarText;
	bool tuningValFound = GetGeneralTuning()->GetTuningString("titleBarText", titleBarText);
	Assert(tuningValFound);

	// Initialize OpenGL
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(kInitialWindowWidth, kInitialWindowHeight);
	glutInitWindowPosition(0, 0);
	glutCreateWindow(titleBarText.c_str());

	// Call the program specific initialization
	Initialize();

	// Set up all of the callback functions.
	glutReshapeFunc(ReshapeFunction);
	glutKeyboardFunc(KeyDownFunction);
	glutKeyboardUpFunc(KeyUpFunction);
	glutDisplayFunc(DisplayFunction);
	//glutSpecialFunc(SpecialKeyDownFunction);
	//glutSpecialUpFunc(SpecialKeyUpFunction);
	glutIdleFunc(DisplayFunction);
	glutPassiveMotionFunc(MouseMoveFunction);
	glutMotionFunc(MouseMoveFunction);
	glutMouseFunc(MouseClickFunc);

	glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);

	InitDisplay();
	InitObjects();

	// Start the event processing loop.
	glutMainLoop();

	ShutdownObjects();
	ShutdownSystems();

	return 0;
}

void InitObjects()
{
	// initialize the Player data.
	cPlayer* pPlayer = GetPlayer();
	pPlayer->MoveTo(0, 0, 0);

  // initialize the LittleGuy data.
  cLittleGuy* pLittleGuy = GetLittleGuy();
  pLittleGuy->MoveTo( (float) RandomX( (int) kSides ) ,
                      (float) RandomY( (int) kSides ) ,
                      kStart + pLittleGuy->getRadius());


	cBillboard* pBillboard = GetBillboard();
	pBillboard->SetSize(1.5f);
	pBillboard->SetImage(gpBackgroundImageData);
}

void ShutdownObjects()
{
	// Doesn't need to do anything right now.
}

//-----------------------------------------------------------------------------
// Desc: Creates all image data needed for the display


//-----------------------------------------------------------------------------
// Desc: This function carries out any program specific initialization as well
//			as any OpenGL state initialization

void InitDisplay()
{
	gpBackgroundImageData = corona::OpenImage("sky.jpg", corona::PF_B8G8R8A8);
	Assert(gpBackgroundImageData && gpBackgroundImageData->getPixels());
	gpBackgroundImageData = corona::FlipImage(gpBackgroundImageData, corona::CA_X);
}
void Initialize()
{
	// get the clear color from tuning
	tVector3f clearColor = {0.0f, 0.0f, 0.0f};
	GetGeneralTuning()->GetTuningFloat("clearColorRed", clearColor[0]);
	GetGeneralTuning()->GetTuningFloat("clearColorGreen", clearColor[1]);
	GetGeneralTuning()->GetTuningFloat("clearColorBlue", clearColor[2]);
	glClearColor(clearColor[0], clearColor[1], clearColor[2], 0.0);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// enable depth buffering (so objects get drawn based on depth instead
	// of the raw draw order)
	glEnable(GL_DEPTH_TEST);

	// cull back faces
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	

	// set up lighting
	glEnable(GL_LIGHTING);
	glShadeModel(GL_FLAT); // GL_SMOOTH

	// turn on ambient and diffuse lighting
	glEnable(GL_LIGHT0);
	GLfloat ambientLight[] = {0.2f, 0.2f, 0.2f, 1.0f };
	GLfloat diffuseLight[] = {0.6f, 0.6f, 0.6f, 1.0f };
	glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); 

	// position the light.
	GLfloat lightPosition[] = {20.0f, 20.0f, 15.0f, 1.0f};
	glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);

	// set up our drawabls to use their color with respect to the ambient
	// and diffuse lights.
	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

	// set up some basic texturing properties
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	// disable the key repeat modes, since we don't want signals sent more
	// than once for the purposes of accelerating input.
	glutIgnoreKeyRepeat(1);
  //this will give you a single stroke signal even if you hold the key
}